package com.zpz.framework.zpzoauth.config.oauth.authorization.exouath.authenticator.partner.zhy;

import com.alibaba.fastjson.JSON;
import com.zpz.framework.zpzoauth.common.encrypt.SignUtil;
import com.zpz.framework.zpzoauth.common.encrypt.sm4.SM4Utils;
import com.zpz.framework.zpzoauth.common.result.ZpzOauthResultMsg;
import com.zpz.framework.zpzoauth.common.result.ZpzOauthResultStatus;
import com.zpz.framework.zpzoauth.common.utils.ZpzOauthHttpUtil;
import com.zpz.framework.zpzoauth.config.oauth.authorization.exouath.ZpzOauthIntegrationAuthentication;
import com.zpz.framework.zpzoauth.config.oauth.authorization.exouath.authenticator.AbstractPreparableIntegrationAuthenticator;
import com.zpz.framework.zpzoauth.pojo.qo.ModifyUserLoginDateQo;
import com.zpz.framework.zpzoauth.pojo.vo.UserAuthenticationVo;
import com.zpz.framework.zpzoauth.service.ZpzOauthFrameUserService;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhangpanzhi
 * @time 2019-07-09
 * @description 未经本人允许请勿随便改动，尊重劳动
 * */
@Component
@Primary
public class ZpzOauthAppLoginAuthenticator extends AbstractPreparableIntegrationAuthenticator {
    private Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private ZpzOauthFrameUserService zpzOauthFrameUserService;
    @Value("${zpzOauth.partner}")
    private String partner;
    private final static String U_P_AUTH_TYPE = "zhy_app_login";
    @Override
    public UserAuthenticationVo authenticate(ZpzOauthIntegrationAuthentication zpzOauthIntegrationAuthenticator) {
        log.info("中海油APP登录：入参："+ JSON.toJSONString(zpzOauthIntegrationAuthenticator));
        ZpzOauthResultMsg<UserAuthenticationVo> resultMsg = zpzOauthFrameUserService.getUserInfoByUserName(zpzOauthIntegrationAuthenticator.getUsername(), zpzOauthIntegrationAuthenticator.getClientId());
        if (resultMsg==null||resultMsg.getCode()!=0){
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]无效的账号");
        }
        UserAuthenticationVo data = resultMsg.getData();
        String[] type = data.getType().split(",");
        if (!Arrays.asList(type).contains("zhy_ksh_wl_app")){
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]无权访问");
        }
        Map<String,Object> partnerStr = (Map<String, Object>) JSON.parse(partner);
        Object zhy = partnerStr.get("zhy");
        if (zhy==null){
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]系统参数配置错误，请联系管理员");
        }
        String mobileNum = zpzOauthIntegrationAuthenticator.getAuthParameter("mobileNum");
        String smsCode = zpzOauthIntegrationAuthenticator.getAuthParameter("smsCode");
        Map<String,Object> zhyStr = (Map<String, Object>) JSON.parse(zhy.toString());
        String appSmsCodeUrl = (String)zhyStr.get("appValidSmsCodeUrl");
        String userNamePwdLoginUrl = (String)zhyStr.get("userNamePwdLoginUrl");
        String appAppId = (String)zhyStr.get("appAppId");
        String operator = (String)zhyStr.get("operator");
        String authKey = (String)zhyStr.get("authKey");
        String appBaowenJiaKey = (String)zhyStr.get("appBaowenJiaKey");
        String appSignKey = (String)zhyStr.get("appSignKey");
        String appSm4Key = (String)zhyStr.get("appSm4Key");
        String timestamp = DateUtils.formatDate(new Date(), "yyyyMMddHHmmss");
        String nonceStr = SignUtil.generateNonceStr(8);
        //请求参数
        Map<String,Object> param1=new HashMap<>();
        param1.put("appId",appAppId);
        param1.put("requestType","1");
        param1.put("epsessionId","");
        param1.put("authType","sms");
        Map<String,String> authPara1=new HashMap<>();
        authPara1.put("mobileNum",mobileNum);
        authPara1.put("smsCode",smsCode);
        param1.put("authPara",authPara1);
        param1.put("device","app");
        param1.put("hostname","127.0.0.1");
        log.info(String.format("请求参数-------%s",JSON.toJSONString(param1)));
        //头部参数
        Map<String,String> header1=new HashMap<>();
        header1.put("operator",operator);
        header1.put("randomstr", nonceStr);
        header1.put("timestamp", timestamp);
        try {
            header1.put("encode", SignUtil.MD5(operator + nonceStr + timestamp+authKey));
        } catch (Exception e) {
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]验证码认证请求签名失败");
        }
        SM4Utils sm4Utils = new SM4Utils();
        sm4Utils.secretKey=appBaowenJiaKey;
        String enParam =sm4Utils.encryptData_ECB(JSON.toJSONString(param1));
        Map<String,String> body=new HashMap<>();
        body.put("u",enParam);
        try {
            header1.put("sign", SignUtil.MD5(appSignKey+JSON.toJSONString(body)));
        } catch (Exception e) {
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]验证码认证请求签名失败");
        }
        String res = null;
        try {
            log.info(String.format("%s-----头部参数-------%s",appSmsCodeUrl,JSON.toJSONString(header1)));
            res = ZpzOauthHttpUtil.getInstance().doPostJsonString(appSmsCodeUrl,null, JSON.toJSONString(body),header1);
            log.info(String.format("响应数据--------%s",res));
        } catch (Exception e) {
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]验证码认证请求异常");
        }
        if (!StringUtils.isNotBlank(res)){
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]验证码认证请求异常");
        }
        Map<String,Object> resMap = (Map<String, Object>) JSON.parse(res);
        String u = resMap.get("u").toString();
        String s = sm4Utils.decryptData_ECB(u);
        log.info(String.format("响应解密数据--------%s",s));
        Map<String,Object> sMap = (Map<String, Object>) JSON.parse(s);
        if (!sMap.get("code").toString().equals("info.common.success")){
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]验证码认证失败");
        }
        Object bodyObj = sMap.get("body");
        if (bodyObj==null){
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]验证码认证失败");
        }
        Map<String,Object> bodyRes =(Map<String, Object>) JSON.parse(bodyObj.toString());
        Object epsessionIdObj = bodyRes.get("epsessionId");
        if (epsessionIdObj==null){
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]验证码认证失败");
        }
        //用户名密码登录
        //请求参数
        Map<String,Object> paramU=new HashMap<>();
        paramU.put("appId",appAppId);
        paramU.put("requestType","1");
        paramU.put("epsessionId",epsessionIdObj);
        paramU.put("authType","pwd");
        Map<String,String> authParaU=new HashMap<>();
        authParaU.put("loginName",zpzOauthIntegrationAuthenticator.getUsername());
        String password = zpzOauthIntegrationAuthenticator.getAuthParameter("password");
        SM4Utils pwdSm4=new SM4Utils();
        pwdSm4.secretKey=appSm4Key;
        authParaU.put("password", pwdSm4.encryptData_ECB(password));
        authParaU.put("encryption_method","SM4");
        paramU.put("authPara",authParaU);
        paramU.put("device","app");
        paramU.put("hostname","app");
        log.info(String.format("请求参数--------%s",JSON.toJSONString(paramU)));
        //头部参数
        Map<String,String> headerU=new HashMap<>();
        headerU.put("operator",operator);
        headerU.put("randomstr", nonceStr);
        headerU.put("timestamp", timestamp);
        try {
            headerU.put("encode", SignUtil.MD5(operator + nonceStr + timestamp+authKey));
        } catch (Exception e) {
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]用户名密码认证请求异常");
        }
        String enParamU =sm4Utils.encryptData_ECB(JSON.toJSONString(paramU));
        Map<String,String> bodyU=new HashMap<>();
        bodyU.put("u",enParamU);
        try {
            headerU.put("sign", SignUtil.MD5(appSignKey+JSON.toJSONString(bodyU)));
        } catch (Exception e) {
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]用户名密码认证请求异常");
        }
        log.info(String.format("%s-----------头部参数--------%s",userNamePwdLoginUrl,JSON.toJSONString(headerU)));
        String resU = null;
        try {
            resU = ZpzOauthHttpUtil.getInstance().doPostJsonString(userNamePwdLoginUrl,null, JSON.toJSONString(bodyU),headerU);
            log.info(String.format("响应数据----------%s",resU));
        } catch (Exception e) {
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]用户名密码认证请求异常");
        }
        if (!StringUtils.isNotBlank(resU)){
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]用户名密码认证失败");
        }
        Map<String,Object> resMapU = (Map<String, Object>) JSON.parse(resU);
        String uU = resMapU.get("u").toString();
        String sU = sm4Utils.decryptData_ECB(uU);
        log.info("响应解密数据--------%s",sU);
        Map<String,Object> sMapU = (Map<String, Object>) JSON.parse(sU);
        if (sMapU.get("code").toString().equals("info.common.success")){
            data.setPassword(passwordEncoder.encode(password));
            ModifyUserLoginDateQo t = new ModifyUserLoginDateQo();
            t.setUserCode(data.getUserCode());
            t.setClientId(zpzOauthIntegrationAuthenticator.getClientId());
            t.setLoginDate(new Date());
            ZpzOauthResultMsg<Boolean> flag = zpzOauthFrameUserService.modifyUserLoginDate(t);
            log.info("::::::::::修改最新登录时间：" + JSON.toJSONString(flag));
            return data;
        } else {
            throw new OAuth2Exception("登录授权失败[ZPZ_DEFINED_OAUTH2_EXCEPTION]["+ ZpzOauthResultStatus.DIY_ERROR__1010.getCode() +"]用户名密码认证失败");
        }
    }
    @Override
    public void prepare(ZpzOauthIntegrationAuthentication integrationAuthentication) {

    }

    @Override
    public boolean support(ZpzOauthIntegrationAuthentication integrationAuthentication) {
    	//增加空判断，支持授权码模式
        return StringUtils.isEmpty(integrationAuthentication.getAuthType())
        		||U_P_AUTH_TYPE.equals(integrationAuthentication.getAuthType());
    }
}
